package com.leonzhangxf.ioc.container.extension;

import com.leonzhangxf.ioc.bean.HelloWorldMessage;
import com.leonzhangxf.ioc.bean.HelloWorldService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * A use demo for {@link BeanPostProcessor}.
 *
 * @author leonzhangxf
 */
@Component
public class HelloWorldBeanPostProcessor implements BeanPostProcessor, Ordered {

    private String helloWorldMessage = "EnableHello world message from bean post-processor.";

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof HelloWorldService) {
            System.out.println(String.format("%s, Post-process before initialization, the bean name is %s.",
                HelloWorldBeanPostProcessor.class.getSimpleName(),
                beanName));

            boolean settled = false;

            // set the message of hello world.
            Field[] declaredFields = bean.getClass().getFields();
            for (Field field : declaredFields) {
                try {
                    if (field.isAnnotationPresent(HelloWorldMessage.class)) {
                        if (!field.isAccessible()) {
                            field.setAccessible(true);
                        }
                        field.set(bean, this.helloWorldMessage);
                        settled = true;
                    }
                } catch (IllegalAccessException e) {
                    throw new HelloWorldBeanFieldException("Could not set the target bean hello world field value.", e);
                }
            }

            if (!settled) {
                Method[] methods = bean.getClass().getDeclaredMethods();
                for (Method method : methods) {
                    if (method.isAnnotationPresent(HelloWorldMessage.class)
                        && method.getParameterCount() == 1
                        && method.getParameterTypes()[0].equals(String.class)
                    ) {
                        try {
                            method.invoke(bean, this.helloWorldMessage);
                        } catch (IllegalAccessException | InvocationTargetException e) {
                            throw new HelloWorldBeanFieldException("Could not invoke setter method for hello world " +
                                "message.", e);
                        }
                    }
                }
            }
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof HelloWorldService) {
            System.out.println(String.format("%s, Post-process after initialization, the bean name is %s.",
                HelloWorldBeanPostProcessor.class.getSimpleName(),
                beanName));
        }
        return bean;
    }

    @Override
    public int getOrder() {
        return 100;
    }

    public void setHelloWorldMessage(String helloWorldMessage) {
        this.helloWorldMessage = helloWorldMessage;
    }
}
